package src.E_Thread;

// 生产者消费者模型

// 实现一（管程法，采用 wait—notify 的方式）
public class E17_wait_notify {
    public static void main(String[] args) {
        // 一个仓库
        BufferingArea bufferingArea = new BufferingArea();
        // 三个生产者
        Producer p1 = new Producer(bufferingArea);
        Producer p2 = new Producer(bufferingArea);
        Producer p3 = new Producer(bufferingArea);
        // 三个消费者
        Consumer c1 = new Consumer(bufferingArea);
        Consumer c2 = new Consumer(bufferingArea);
        Consumer c3 = new Consumer(bufferingArea);
        // 启动线程
        new Thread(p1,"1号员工").start();
        new Thread(p2,"2号员工").start();
        new Thread(p3,"3号员工").start();
        new Thread(c1,"1号顾客").start();
        new Thread(c2,"2号顾客").start();
        new Thread(c3,"3号顾客").start();
    }
}

// 生产者
class Producer implements Runnable{
    private BufferingArea bufferingArea;

    public Producer(BufferingArea bufferingArea) {
        this.bufferingArea = bufferingArea;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(10); // 控制通货膨胀的开关哈哈
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            bufferingArea.set();
        }
    }
}

// 消费者
class Consumer implements Runnable{
    private BufferingArea bufferingArea;

    public Consumer(BufferingArea bufferingArea) {
        this.bufferingArea = bufferingArea;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            bufferingArea.get();
        }
    }
}

// 缓冲区（仓库）
class BufferingArea{
    private int max = 10; // 仓库产品最大容量
    private int count = 0; // 仓库当前产品数量
    // 生产
    public synchronized void set(){
        if(count < max){
            count++;
            System.out.println(Thread.currentThread().getName()+"生产了一件产品，当前仓库还有"+count+"件商品");
            notifyAll(); // 唤醒所有wait的线程，notify()方法——随机唤醒一个wait的线程
        } else {
            try {
                System.out.println("当前仓库已满，请等待消费者消费，数量："+count);
                wait(); // 线程会同时释放锁，必须配合synchronized使用，且使用的必须为同一个对象
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    // 消费
    public synchronized void get(){
        if(count > 0){
            System.out.println(Thread.currentThread().getName()+" 消费了第 "+count+" 件商品");
            count--;
            notifyAll(); // 唤醒所有wait的线程，notify()方法——随机唤醒一个wait的线程
        } else {
            try {
                System.out.println("当前仓库无商品，请等待生产者生产，数量："+count);
                wait(); // 线程会同时释放锁，必须配合synchronized使用，且使用的必须为同一个对象
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}